package com.fmistuff.threadedcalc.ui;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.math.BigInteger;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.security.auth.kerberos.KerberosKey;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import com.fmistuff.chain.nodes.TermNode;
import com.fmistuff.threadedcalc.Calculator;

public class CalcFrame extends JFrame {

	private static final long serialVersionUID = -7202417515015931473L;

	private Dimension windowDimensions;
	private JTextField expressionField;
	private JButton generateButton;
	private JButton calculateJavaScriptButton;
	private JButton calculateButton;

	private JTextField resultFieldJavascript;
	private JTextArea logArea;
	private ILoggable loggable;
	private ScriptEngine javaScriptEngine = new ScriptEngineManager()
			.getEngineByName("JavaScript");

	private JTextField resultField;

	private JComboBox<String> threadSelector;

	private JFileChooser filePicker;

	private JFrame filePickerFrame;

	private JLabel selectedFile;

	private JButton pickAFileBUtton;

	private JCheckBox noDivisionsCheckBox;

	public CalcFrame() {
		initWindow();
		initUI();

		loggable = new Log();
	}

	private void initUI() {
		JPanel gridPanel = new JPanel();
		gridPanel.setLayout(new GridLayout(0, 2, 10, 5));

		generateButton = new JButton("Generate");
		generateButton.addActionListener(new SimpleActionListener(
				new GenerateButtonActivatable()));

		gridPanel.add(generateButton);

		expressionField = new JTextField();
		expressionField.setColumns(25);

		gridPanel.add(expressionField);

		pickAFileBUtton = new JButton("Pick a file");
		pickAFileBUtton.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				filePickerFrame.setVisible(true);
			}
		});
		gridPanel.add(pickAFileBUtton);

		selectedFile = new JLabel("None selected");
		gridPanel.add(selectedFile);

		filePicker = new JFileChooser();
		filePickerFrame = new JFrame();
		filePicker.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				filePickerFrame.setVisible(false);
				selectedFile.setText(filePicker.getSelectedFile()
						.getAbsolutePath());

				// update the other form
				if (filePicker.getSelectedFile() != null) {
					String expr = null;
					File exprFile = filePicker.getSelectedFile();
					char[] cbuff = new char[(int) exprFile.length()];
					try {
						new FileReader(exprFile).read(cbuff, 0,
								(int) exprFile.length());
						expr = new String(cbuff);
						updateExpressionField(expr);
					} catch (IOException e1) {
						e1.printStackTrace();
					}
				}

			}
		});
		filePickerFrame.add(filePicker);
		filePickerFrame.pack();

		calculateJavaScriptButton = new JButton("Calculate (JavaScript)");
		calculateJavaScriptButton.addActionListener(new SimpleActionListener(
				new CalculateJavascriptButtonActivatable()));

		gridPanel.add(calculateJavaScriptButton);

		resultFieldJavascript = new JTextField();
		resultFieldJavascript.setColumns(25);

		gridPanel.add(resultFieldJavascript);

		calculateButton = new JButton("Calculate");
		calculateButton.addActionListener(new SimpleActionListener(
				new CalculateButtonActivatable()));
		gridPanel.add(calculateButton);

		resultField = new JTextField();
		resultField.setColumns(25);
		gridPanel.add(resultField);

		JLabel label = new JLabel();
		label.setText("Select number of threads");
		gridPanel.add(label);

		String treads[] = new String[] { "1", "2", "3", "4", "5", "6", "7", "8" };
		threadSelector = new JComboBox<String>(treads);
		gridPanel.add(threadSelector);

		add(gridPanel);
		
		JLabel noDivisions = new JLabel("No divisions: (will be replaced with *)");
		gridPanel.add(noDivisions);
		
		noDivisionsCheckBox = new JCheckBox();
		gridPanel.add(noDivisionsCheckBox);
		
		logArea = new JTextArea();
		logArea.setColumns(50);
		logArea.setEditable(false);
		add(logArea);
		
		JPanel threePanel = new JPanel();
		threePanel.setLayout(new GridLayout(0, 3,10,5));
		
		JButton clearLog = new JButton("Clear log");
		clearLog.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				loggable.clear();
				updateLogText(loggable.getText());
			}
		});
		threePanel.add(clearLog);

		pack();
	}

	protected void updateLogText(String text) {
		logArea.setText(text);
	}

	private void initWindow() {
		final Dimension ourDimension = Toolkit.getDefaultToolkit()
				.getScreenSize();
		final Dimension maxDimensions = new Dimension(ourDimension);
		log(maxDimensions);

		ourDimension.height >>= 1;
		ourDimension.width >>= 1;

		this.windowDimensions = ourDimension;

		setSize(ourDimension);

		// set location in center
		setLocation((maxDimensions.width - ourDimension.width) / 2,
				(maxDimensions.height - ourDimension.height) / 2);
		setDefaultCloseOperation(EXIT_ON_CLOSE);

		setResizable(false);

		setUndecorated(false);
		setVisible(true);
		setAlwaysOnTop(false);

		setLayout(new GridLayout(0, 1, 10, 10));
	}

	private void log(Dimension ourDimension) {
		System.out.println("Height: " + ourDimension.height);
		System.out.println("Width: " + ourDimension.width);
	}

	@Override
	public void paint(Graphics g) {
		super.paint(g);
		setTitle("Threaded calc");
	}

	private void onGenerate() {
		System.out.println("Generate activated");
		final String generatedExpression = new TermNode().descend();
		updateExpressionField(generatedExpression);

	}

	private void updateExpressionField(final String generatedExpression) {
		StringBuffer buffer = new StringBuffer(generatedExpression);
		if (noDivisionsCheckBox.isSelected()){
			for (int i = 0; i < generatedExpression.length(); i++){
				if (buffer.charAt(i)=='/'){
					buffer.setCharAt(i, '*');
				}
			}
		}
		expressionField.setText(buffer.toString());
	}

	private void onCalculateJavascript() {
		try {
			long start = System.currentTimeMillis();
			final String result = String.valueOf(javaScriptEngine
					.eval(expressionField.getText()));
			resultFieldJavascript.setText(result);
			long end = System.currentTimeMillis();
			loggable.log("Time for calculations(javascript): " + (end - start)
					/ 1.0f + " milleseconds");
			updateLogText(loggable.getText());
		} catch (ScriptException e) {
			e.printStackTrace();
		} catch (ClassCastException e) {
			e.printStackTrace();
		}

	}

	private class GenerateButtonActivatable implements IActivatable {
		@Override
		public void activate() {
			onGenerate();
		}
	}

	private class CalculateJavascriptButtonActivatable implements IActivatable {
		@Override
		public void activate() {
			onCalculateJavascript();
		}
	}

	private class CalculateButtonActivatable implements IActivatable {
		@Override
		public void activate() {
			onCalculate();
		}

		private void onCalculate() {
			String expression = expressionField.getText();
			BigInteger result = Calculator.calculate(expression,
					threadSelector.getSelectedIndex() + 1, loggable);
			resultField.setText(result.toString());
			updateLogText(loggable.getText());
		}
	}

}
